﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Xml.Linq;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using Directory=Lucene.Net.Store.Directory;

namespace SPSearch.LuceneIndexing.SiteSearch
{
    public class SearchPage : Page
    {
        protected Xml XslTransformer;

        protected override void OnLoad(EventArgs e)
        {
            XslTransformer.TransformSource = SPUtility.GetGenericSetupPath(@"TEMPLATE\LAYOUTS\SPSearch\SiteSearch.xslt");
            
            var xml = new XElement("Control");

            var indexDirectory = IndexDirectory();
            var reader = IndexReader.Open(indexDirectory, true);

            xml.Add(ContentTypes(reader));

            if (Page.IsPostBack)
            {
                xml.Add(new XAttribute("SearchAttempted", true));

                var textToSearchFor = HttpContext.Current.Request.Form["SearchText"];
                xml.Add(new XAttribute("SearchText", textToSearchFor));

                var contentTypeFilter = HttpContext.Current.Request.Form["ContentTypeFilter"];
                xml.Add(new XAttribute("SelectedContentType", contentTypeFilter));

                if (!string.IsNullOrEmpty(textToSearchFor))
                {
                    var searcher = new IndexSearcher(indexDirectory, true);
                    xml.Add(SearchResults(reader, searcher, textToSearchFor.ToLowerInvariant(), contentTypeFilter));
                }
            }
            
            XslTransformer.DocumentContent = xml.ToString();
        }

        private static IEnumerable<XElement> ContentTypes(IndexReader reader)
        {
            var termEnum = reader.Terms(new Term("ContentType", string.Empty));

            yield return new XElement("ContentType", new XText(termEnum.Term().Text()));
            while (termEnum.Next() && termEnum.Term().Field().Equals("ContentType"))
                yield return new XElement("ContentType", new XText(termEnum.Term().Text()));
        }

        private static Directory IndexDirectory()
        {
            var indexPath = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default].Path
                + @"\Resources\LuceneIndex";
            return FSDirectory.Open(new DirectoryInfo(indexPath));
        }

        private static IEnumerable<XElement> SearchResults(IndexReader reader, Searcher searcher, string textToSearchFor, string contentTypeFilter)
        {
            var query = new BooleanQuery();
            query.Add(new WildcardQuery(new Term("Title", string.Format("*{0}*", textToSearchFor))), BooleanClause.Occur.SHOULD);
            query.Add(new WildcardQuery(new Term("BodyCopy", string.Format("*{0}*", textToSearchFor))), BooleanClause.Occur.SHOULD);
            query.Add(new WildcardQuery(new Term("Reusable HTML", string.Format("*{0}*", textToSearchFor))), BooleanClause.Occur.SHOULD);
            query.Add(new WildcardQuery(new Term("Comments", string.Format("*{0}*", textToSearchFor))), BooleanClause.Occur.SHOULD);

            var results = searcher.Search(query, 100).scoreDocs.Select(d => reader.Document(d.doc));
            if (!string.IsNullOrEmpty(contentTypeFilter))
                results = results.Where(d => d.GetField("ContentType").StringValue().Equals(contentTypeFilter));

            foreach (var document in results)
            {
                yield return new XElement("Result",
                    new XAttribute("Title", document.GetField("Title").StringValue()),
                    new XAttribute("ContentType", document.GetField("ContentType").StringValue()),
                    new XAttribute("Created", document.GetField("Created") != null 
                        ? DateTime.Parse(document.GetField("Created").StringValue()).ToString("dd/MM/yyyy") 
                        : string.Empty),
                    new XAttribute("Modified", document.GetField("Modified") != null
                        ? DateTime.Parse(document.GetField("Modified").StringValue()).ToString("dd/MM/yyyy")
                        : string.Empty),
                    new XAttribute("Web", document.GetField("WebUrl").StringValue()),
                    new XAttribute("List", document.GetField("ListTitle").StringValue()),
                    new XAttribute("Path", document.GetField("ItemUrl").StringValue()));
            }

            searcher.Close();
            reader.Close();
        }
    }
}
